home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 264_01 / du.c < prev    next >
Text File  |  1980-01-01  |  6KB  |  253 lines

  1. /*
  2.  * du - summarize disk usage
  3.  *
  4.  * Displays the number of kilobytes used by all files and, recursively,
  5.  * directories within each specified directory or filename.
  6.  *
  7.  * Usage: du [-as] [path...]
  8.  *
  9.  * Flags:
  10.  * -a   display an entry for all files
  11.  * -s   display only the grand total
  12.  *
  13.  * Default action is to display an entry for each directory only.
  14.  * Default path is ".".
  15.  *
  16.  * This program is in the public domain.
  17.  * David MacKenzie
  18.  * 6522 Elgin Lane
  19.  * Bethesda, MD 20817
  20.  *
  21.  * Latest revision: 05/03/88
  22.  */
  23.  
  24. #include <ctype.h>
  25. #ifndef tolower
  26. #define tolower(s) _tolower(s)
  27. #endif
  28. #include "getdir.h"
  29.  
  30. /* For dynamically allocating space to store contents of each directory. */
  31. #define ENTRIES_INCR 25
  32.  
  33. /*
  34.  * kbytes(b)
  35.  *     int b;
  36.  * Macro to return the number of kilobytes (rounded up) taken by a given
  37.  * number of bytes.
  38.  */
  39. #define kbytes(b) ((b) / 1024 + ((b) % 1024 != 0))
  40.  
  41. /* Shortened format for array in memory, to save space */
  42. struct sablk {
  43.     char    sa_attrib;
  44.     unsigned long sa_fsize;
  45.     char    sa_fname[13];
  46. };
  47.  
  48. char    dirbuf[512];        /* Buffer for disk input. */
  49.  
  50. int     allfiles = 0;        /* -a flag. */
  51. int     summary = 0;        /* -s flag. */
  52.  
  53. char   *
  54. malloc(), *realloc();
  55.  
  56. _main(argc, argv)
  57.     int     argc;
  58.     char  **argv;
  59. {
  60.     int     optind;        /* Loop index. */
  61.  
  62.     for (optind = 1; optind < argc && *argv[optind] == '-'; ++optind) {
  63.     while (*++argv[optind]) {
  64.         switch (*argv[optind]) {
  65.         case 'a':
  66.         allfiles = 1;
  67.         break;
  68.         case 's':
  69.         summary = 1;
  70.         break;
  71.         default:
  72.         printf("Usage: du [-as] [path...]\n");
  73.         exit(1);
  74.         break;
  75.         }
  76.     }
  77.     }
  78.  
  79.     if (optind == argc)
  80.     (void) dudir(".", 1);
  81.     else
  82.     for (; optind < argc; ++optind)
  83.         (void) dudir(argv[optind], 1);
  84.  
  85.     exit(0);
  86. }
  87.  
  88. /*
  89.  * Calculate usage for one directory.  Calls itself recursively
  90.  * on subdirectories.  Returns number of kilobytes taken by the files
  91.  * and, recursively, directories in path.
  92.  */
  93.  
  94. dudir(path, root_call)
  95.     char   *path;        /* Can contain wildcards. */
  96.     char    root_call;        /* Was this invocation from main()? */
  97. {
  98.     char   *basename();
  99.     struct sablk *initarray(), *saveent();
  100.     struct ffblk *dir = (struct ffblk *) dirbuf;
  101.     struct sablk *save_array;    /* Array of dir entries. */
  102.     int     last_entry = -1;    /* Last valid entry of save_array. */
  103.     char    tmppath[125];    /* For tacking various things onto path. */
  104.     char   *tail;        /* For isolating leading dirs in path. */
  105.     int     kb;            /* Temporary for calculation. */
  106.     int     total_kbytes = 0;    /* Size of this directory. */
  107.     int     i;            /* Loop index. */
  108.  
  109.     /*
  110.      * The following kludge is necessary because the MS-DOS globbing routines
  111.      * (getfirst and getnext) don't recognize any of these directories on
  112.      * their own. 
  113.      */
  114.     (void) strcpy(tmppath, path);
  115.     if (isroot(tmppath)) {
  116.     (void) strcat(tmppath, "*.*");
  117.     kb = dudir(tmppath, 0);
  118.     if (!summary || root_call)
  119.         printf("%d\t%s\n", kb, path);
  120.     total_kbytes += kb;
  121.     } else if (isdot(tmppath)) {
  122.     (void) strcat(tmppath, "\\*.*");
  123.     kb = dudir(tmppath, 0);
  124.     if (!summary || root_call)
  125.         printf("%d\t%s\n", kb, path);
  126.     total_kbytes += kb;
  127.     } else {
  128.     save_array = initarray();
  129.  
  130.         setdta(dirbuf);
  131.         
  132.     for (i = getfirst(tmppath, FA_ALL); !i; i = getnext(tmppath, FA_ALL))
  133.         save_array = saveent(save_array, dir, ++last_entry);
  134.  
  135.     /* Overwrite any last element of path (e.g. "*.*") with the name. */
  136.     tail = basename(tmppath);
  137.  
  138.     for (i = 0; i <= last_entry; ++i) {
  139.         if ((save_array[i].sa_attrib & FA_DIREC)) {
  140.         if (save_array[i].sa_fname[0] != '.') {
  141.             (void) strcpy(tail, save_array[i].sa_fname);
  142.             (void) strcat(tmppath, "\\*.*");
  143.             kb = dudir(tmppath, 0);
  144.             if (!summary || root_call) {
  145.             *tail = 0;
  146.             printf("%d\t%s%s\n", kb, tmppath,
  147.             save_array[i].sa_fname);
  148.             }
  149.             total_kbytes += kb;
  150.         }
  151.         } else {
  152.         /* Normal file. */
  153.         kb = kbytes(save_array[i].sa_fsize);
  154.         if (allfiles) {
  155.             *tail = 0;
  156.             printf("%d\t%s%s\n", kb, tmppath, save_array[i].sa_fname);
  157.         }
  158.         total_kbytes += kb;
  159.         }
  160.     }
  161.     (void) free(save_array);
  162.     }
  163.  
  164.     return total_kbytes;
  165. }
  166.  
  167. struct sablk *
  168. initarray()
  169. {
  170.     struct sablk *save_array;
  171.  
  172.     save_array = (struct sablk *)
  173.     malloc(sizeof(struct sablk) * ENTRIES_INCR);
  174.     if (!save_array) {
  175.     perror("malloc");
  176.     exit(1);
  177.     }
  178.     return save_array;
  179. }
  180.  
  181. struct sablk *
  182. saveent(save_array, dir, last_entry)
  183.     struct sablk *save_array;
  184.     struct ffblk *dir;
  185.     int     last_entry;
  186. {
  187.     char   *normalize();
  188.  
  189.     if (last_entry > 0 && last_entry % ENTRIES_INCR == 0) {
  190.     save_array = (struct sablk *)
  191.         realloc(save_array, sizeof(struct sablk) *
  192.         (last_entry + ENTRIES_INCR));
  193.     if (!save_array) {
  194.         perror("realloc");
  195.         exit(1);
  196.     }
  197.     }
  198.     save_array[last_entry].sa_attrib = dir->ff_attrib;
  199.     save_array[last_entry].sa_fsize = dir->ff_fsize;
  200.     (void) strcpy(save_array[last_entry].sa_fname, normalize(dir->ff_fname));
  201.     return save_array;
  202. }
  203.  
  204. /*
  205.  * Return true if the path has the form "d:" or "\" or "d:\".
  206.  */
  207. isroot(p)
  208.     char   *p;
  209. {
  210.     int     i = strlen(p);
  211.  
  212.     return i == 2 && p[1] == ':' ||
  213.     !strcmp(p, "\\") ||
  214.     i == 3 && !strcmp(p + 1, ":\\");
  215. }
  216.  
  217. /*
  218.  * Return true if the path has the form:
  219.  * ".." or "d:.." or "." or "d:." or "\." or "d:\.".
  220.  */
  221. isdot(p)
  222.     char   *p;
  223. {
  224.     int     i = strlen(p);
  225.  
  226.     return !strcmp(p, "..") ||
  227.     i == 4 && !strcmp(p + 1, ":..") ||
  228.     !strcmp(p, ".") ||
  229.     i == 3 && !strcmp(p + 1, ":.") ||
  230.     !strcmp(p, "\\.") ||
  231.     i == 4 && !strcmp(p + 1, ":\\.");
  232. }
  233.  
  234. /*
  235.  * Convert uppercase letters to lowercase, and non-graphic characters to '?'.
  236.  * Return the argument.
  237.  */
  238.  
  239. char   *
  240. normalize(s)
  241.     char   *s;
  242. {
  243.     char   *t;
  244.  
  245.     for (t = s; *t; ++t)
  246.     if (!isascii(*t) || !isgraph(*t))
  247.         *t = '?';
  248.     else if (isupper(*t) && *t != '_')
  249.         /* Aztec C's ctype thinks that isupper('_') is true . . . */
  250.         *t = tolower(*t);
  251.     return s;
  252. }
  253.